package com.demo.log;

import org.slf4j.LoggerFactory;
import org.slf4j.Marker;

import java.util.concurrent.atomic.AtomicLong;


/**
 * @author wangfengchen
 */
public interface Logger extends org.slf4j.Logger {

    boolean isInfoEnabled(long now);

    boolean isWarnEnabled(long now);

    boolean isErrorEnabled(long now);

    /**
     * 默认各类日志5s输出一次
     *
     * @param clazz
     */
    static Logger get(Class<?> clazz) {
        return new IntervalLogger(clazz);
    }

    /**
     * @param clazz
     * @param interval 日志输出时间间隔(ms)
     */
    static Logger get(Class<?> clazz, long interval) {
        return new IntervalLogger(clazz);
    }

    class IntervalLogger implements Logger {
        private final org.slf4j.Logger logger;
        private final long interval;
        private AtomicLong lastInfoTs = new AtomicLong(0); // 上次Info输出时间
        private AtomicLong lastWarnTs = new AtomicLong(0); // 上次Warn输出时间
        private AtomicLong lastErrorTs = new AtomicLong(0); // 上次Error输出时间

        public IntervalLogger(Class<?> clazz) {
            this(clazz, 60_000);
        }

        public IntervalLogger(Class<?> clazz, long interval) {
            this.logger = LoggerFactory.getLogger(clazz);
            this.interval = interval;
        }

        @Override
        public String getName() {
            return logger.getName();
        }

        @Override
        public void info(String msg) {
            logger.info(msg);
        }

        @Override
        public void info(String format, Object arg) {
            logger.info(format, arg);
        }

        @Override
        public void info(String format, Object arg1, Object arg2) {
            logger.info(format, arg1, arg2);
        }

        @Override
        public void info(String format, Object... arguments) {
            logger.info(format, arguments);
        }

        @Override
        public void info(String msg, Throwable t) {
            logger.info(msg, t);
        }

        @Override
        public boolean isInfoEnabled(Marker marker) {
            return logger.isInfoEnabled(marker);
        }

        @Override
        public void info(Marker marker, String msg) {
            logger.info(marker, msg);
        }

        @Override
        public void info(Marker marker, String format, Object arg) {
            logger.info(marker, format, arg);
        }

        @Override
        public void info(Marker marker, String format, Object arg1, Object arg2) {
            logger.info(marker, format, arg1, arg2);
        }

        @Override
        public void info(Marker marker, String format, Object... arguments) {
            logger.info(marker, format, arguments);
        }

        @Override
        public void info(Marker marker, String msg, Throwable t) {
            logger.info(marker, msg, t);
        }

        @Override
        public void warn(String msg) {
            logger.warn(msg);
        }

        @Override
        public void warn(String format, Object arg) {
            logger.warn(format, arg);
        }

        @Override
        public void warn(String format, Object... arguments) {
            logger.warn(format, arguments);
        }

        @Override
        public void warn(String format, Object arg1, Object arg2) {
            logger.warn(format, arg1, arg2);
        }

        @Override
        public void warn(String msg, Throwable t) {
            logger.warn(msg, t);
        }

        @Override
        public boolean isWarnEnabled(Marker marker) {
            return logger.isWarnEnabled(marker);
        }

        @Override
        public void warn(Marker marker, String msg) {
            logger.warn(marker, msg);
        }

        @Override
        public void warn(Marker marker, String format, Object arg) {
            logger.warn(marker, format, arg);
        }

        @Override
        public void warn(Marker marker, String format, Object arg1, Object arg2) {
            logger.warn(marker, format, arg1, arg2);
        }

        @Override
        public void warn(Marker marker, String format, Object... arguments) {
            logger.warn(marker, format, arguments);
        }

        @Override
        public void warn(Marker marker, String msg, Throwable t) {
            logger.warn(marker, msg, t);
        }

        @Override
        public void error(String msg) {
            logger.error(msg);
        }

        @Override
        public void error(String format, Object arg) {
            logger.error(format, arg);
        }

        @Override
        public void error(String format, Object arg1, Object arg2) {
            logger.error(format, arg1, arg2);
        }

        @Override
        public void error(String format, Object... arguments) {
            logger.error(format, arguments);
        }

        @Override
        public void error(String msg, Throwable t) {
            logger.error(msg, t);
        }

        @Override
        public boolean isErrorEnabled(Marker marker) {
            return logger.isErrorEnabled(marker);
        }

        @Override
        public void error(Marker marker, String msg) {
            logger.error(marker, msg);
        }

        @Override
        public void error(Marker marker, String format, Object arg) {
            logger.error(marker, format, arg);
        }

        @Override
        public void error(Marker marker, String format, Object arg1, Object arg2) {
            logger.error(marker, format, arg1, arg2);
        }

        @Override
        public void error(Marker marker, String format, Object... arguments) {
            logger.error(marker, format, arguments);
        }

        @Override
        public void error(Marker marker, String msg, Throwable t) {
            logger.error(marker, msg, t);
        }

        @Override
        public boolean isTraceEnabled() {
            return false;
        }

        @Override
        public void trace(String msg) {
        }

        @Override
        public void trace(String format, Object arg) {
        }

        @Override
        public void trace(String format, Object arg1, Object arg2) {
        }

        @Override
        public void trace(String format, Object... arguments) {
        }

        @Override
        public void trace(String msg, Throwable t) {
        }

        @Override
        public boolean isTraceEnabled(Marker marker) {
            return false;
        }

        @Override
        public void trace(Marker marker, String msg) {
        }

        @Override
        public void trace(Marker marker, String format, Object arg) {
        }

        @Override
        public void trace(Marker marker, String format, Object arg1, Object arg2) {
        }

        @Override
        public void trace(Marker marker, String format, Object... argArray) {
        }

        @Override
        public void trace(Marker marker, String msg, Throwable t) {
        }

        @Override
        public boolean isDebugEnabled() {
            return false;
        }

        @Override
        public void debug(String msg) {
        }

        @Override
        public void debug(String format, Object arg) {
        }

        @Override
        public void debug(String format, Object arg1, Object arg2) {
        }

        @Override
        public void debug(String format, Object... arguments) {
        }

        @Override
        public void debug(String msg, Throwable t) {
        }

        @Override
        public boolean isDebugEnabled(Marker marker) {
            return false;
        }

        @Override
        public void debug(Marker marker, String msg) {
        }

        @Override
        public void debug(Marker marker, String format, Object arg) {
        }

        @Override
        public void debug(Marker marker, String format, Object arg1, Object arg2) {
        }

        @Override
        public void debug(Marker marker, String format, Object... arguments) {
        }

        @Override
        public void debug(Marker marker, String msg, Throwable t) {
        }

        @Override
        public boolean isInfoEnabled() {
            return isInfoEnabled(System.currentTimeMillis());
        }

        @Override
        public boolean isWarnEnabled() {
            return isWarnEnabled(System.currentTimeMillis());
        }

        @Override
        public boolean isErrorEnabled() {
            return isErrorEnabled(System.currentTimeMillis());
        }

        @Override
        public boolean isInfoEnabled(long now) {
            return logger.isInfoEnabled() && cas(lastInfoTs, now);
        }

        @Override
        public boolean isWarnEnabled(long now) {
            return logger.isWarnEnabled() && cas(lastWarnTs, now);
        }

        @Override
        public boolean isErrorEnabled(long now) {
            return logger.isErrorEnabled() && cas(lastErrorTs, now);
        }

        private boolean cas(AtomicLong lastTs, long now) {
            long ts = lastTs.get();
            return (now - ts >= interval && lastTs.compareAndSet(ts, now));
        }
    }


}